#ifndef BLOQUEARBOL_H_
#define BLOQUEARBOL_H_

#include <vector>
#include "../../Objeto.h"
#include "../../Constantes.h"
#include "../../claves/Key.h"
#include "../Elemento.h"
#include "../../claves/TipoClave.h"

class Arbol;
class Bytes;
class Objeto;

using namespace std;
/* BloqueArbol se serializa:
 *tipo|id|padre|espaciolibre|claves|punteros
 */

class BloqueArbol: public Objeto {
protected:
	TipoClave* extractor;
	char tipo;
	offset id; /* # de bloque en el archivoBloqueArbol*/
	offset padre; /* # de bloque del padre siempre es un interno.*/
	vector<Key> claves;
	vector<offset> punteros;
	cantBytes tamanio;
	bool modificado;
	bool borrado;
	unsigned cantClavesMax;

public:
	/*
	 * Pre: -
	 * Pos: Crea una nueva instancia.
	 */
	BloqueArbol(Arbol* a, cantBytes tamanio,TipoClave* extractor);
	/*
	 * Pre: -
	 * Pos: Libera los recursos instanciados.
	 */
	virtual ~BloqueArbol();

	/*
	 * Pre: -
	 * Pos: Devuelve la cantidad de claves.
	 */

	unsigned getCantClaves();
	/*
	 * Pre: -
	 * Pos: Devuelve el tipo de bloque.
	 */
	virtual char getTipo() = 0;

	unsigned getCantClavesMax();
	unsigned getCantClavesMin();
	/*
	 * Pre: -
	 * Pos: devuelve el id (numero de componente en el archivo) del bloque.
	 */
	offset getId();

	/*se setean las claves al vector propio de this de claves*/
	void setClaves(const std::vector<Key>& vector);

	void setTamanio(cantBytes tam);
	/*
	 * Pre: -
	 * Pos: devuelve el id del padre.
	 */
	offset getPadre();

	/*
	 * Pre: -
	 * Pos: devuelve el vector con las claves.
	 */
	vector<Key> &getClaves();

	/*
	 * Pre: -
	 * Pos: devuelve el vector con las punteros.
	 */
	vector<offset> &getPunteros();

	void setPunteros(const vector<offset>& vector);
	/*
	 * Pre: -
	 * Pos: setea el id del bloque.
	 */
	void setId(offset id);

	/*
	 * Pre: -
	 * Pos: Setea el id del padre.
	 */
	void setPadre(offset padre);

	/*
	 * Pre: -
	 * Pos: serializa el bloque.
	 */
	virtual Bytes serializarse();

	/*
	 * Pre: -
	 * Pos: hidrata el bloque.
	 */
	virtual bool hidratarse(const Bytes& bytes);

	/*
	 * Pre: -
	 * Pos: si uno modifica el bloque debe llamar antes a esta funcion. sirve
	 * para saber si el bloque fue modificado y debe guardarse la modificacion en disco.
	 */
	void setModificado();

	/*
	 * Pre: -
	 * Pos: devuelve true si el objeto se setio como modificado.
	 */
	bool getModificado();

	/*Retorna la clave mayor del nodo*/
	Key getClaveMayor() const;

	/*Se retorna si el nodo esta seteado para borrarse o no*/
	bool getBorrado();

	/*Se setea si el nodo esta seteado para borrarse o no*/
	void setBorrado();

	/*cuando se le setean nuevos hijos a los nodos internos,esto debera reflejarse en los valores de claves*/

	void actualizarClaves();

	/*Intercambio claves en mi lista de clave*/
	virtual void cambiarClave(Key claveAnterior, Key claveNueva);

	/*Retorno el nodo donde estaba ese elemento que se inserto,
	 * el resultado de la operacion se retorna res, Si no se pue realizar la operacion
	 * en el retorno se devuelve NULL */
	virtual BloqueArbol* insertarElemento(const Elemento& elemento,
			Resultado& res, bool& overflow)=0;

	/*Retorno el nodo donde estaba ese elemento que se removio,
	 * el resultado de la operacion se retorna res(RES_OK o RES_INEXISTENTE), Si no se pue realizar la operacion
	 * en el retorno se devuelve NULL */
	virtual BloqueArbol* removerElemento(const Elemento& elemento,
			Resultado& res)=0;

	/*Retorna el hijo menor que  contiene el Nodo*/
	virtual BloqueArbol* getHijoMenor()=0;

	/*Le paso una clave que estoy buscando, el me devolvera el puntero correspondiente al Elemento
	 * si no lo encuentra devuelve null */
	virtual offset getElemento(const Key& clave, Resultado& res)=0;

	/*retorna un puntero al nodo que debe tener a esa clave*/
	virtual BloqueArbol* buscarHijo(const Key& clave)=0;

	/*se retorna la mayor clave de la rama que surge desde ahi*/
	virtual Key getMayorDeRama()=0;

	/*segun tamanio de todas las claves de this y de otro nodo se determina si juntos quedan en estado de overflow*/
	bool existeOverflow(unsigned int cant1);

	/*segun tamanio de todas las claves de  y de otro nodo se determina si juntos quedan en estado de underflow*/
	bool existeUnderflow(unsigned int cant1);

	/*retorna las claves en un string*/
	virtual std::string clavesToString() =0;

	/*se imprimen las claves del vector por consola*/
	virtual void imprimir()=0;
	offset getAdan();

	static cantBytes calcularTamanio(cantBytes cantClaves, cantBytes tamMaximoClave);

	Arbol* getArbol();
	/*
	 * Pre: -
	 * Pos: devuelve el tamanio del bloque serializado.
	 */
	cantBytes getTamanio();
	void nuevosHijos(offset viejo);
	void nuevosHijos();
protected:
	Arbol* arbol;
	/*
	 * Pre: -
	 * Pos: serializa las claves del bloque.
	 */
	Bytes serializarClaves();

	/*
	 * Pre: -
	 * Pos: serializa los punteros del bloque.
	 */
	Bytes serializarPunteros();

	/*
	 * Pre: -
	 * Pos: hidrata las claves del bloque.
	 */
	offset hidratarClaves(Bytes datosClaves,cantBytes cantClaves);

	/*
	 * Pre: -
	 * Pos: hidrata los punteros del bloque.
	 */
	bool hidratarPunteros(Bytes datoPunteros);

};


void BalancearDos(BloqueArbol* nodo, BloqueArbol* hermano, bool dosAUno);


 void BalancearTres(BloqueArbol* hermanoIzq, BloqueArbol* nodo,
		BloqueArbol* hermano, bool tresADos);
#endif /* BLOQUEARBOL_H_ */
